package com.xuecheng.content.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.CourseBaseDTO;
import com.xuecheng.api.content.model.dto.CourseTeacherDTO;
import com.xuecheng.api.content.model.dto.TeachplanDTO;
import com.xuecheng.api.system.model.dto.CourseCategoryDTO;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.CourseModeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.JsonUtil;
import com.xuecheng.content.agent.SystemApiAgent;
import com.xuecheng.content.common.constant.ContentErrorCode;
import com.xuecheng.content.common.constant.CoursePubTemplateKey;
import com.xuecheng.content.convert.CoursePubConvert;
import com.xuecheng.content.entity.CourseBase;
import com.xuecheng.content.entity.CourseMarket;
import com.xuecheng.content.entity.CoursePub;
import com.xuecheng.content.entity.CoursePubMsg;
import com.xuecheng.content.mapper.CoursePubMapper;
import com.xuecheng.content.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 课程发布 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CoursePubServiceImpl extends ServiceImpl<CoursePubMapper, CoursePub> implements CoursePubService {

    @Autowired
    private CourseBaseService courseBaseService;
    @Autowired
    private CourseMarketService courseMarketService;
    @Autowired
    private CourseTeacherService courseTeacherService;
    @Autowired
    private TeachplanService teachplanService;
    @Autowired
    private SystemApiAgent systemApiAgent;
    @Autowired
    private CoursePubMsgService coursePubMsgService;

    @Autowired
    private RabbitTemplate rabbitTemplate;


    @Value("${course.publish.exchange}")
    private String exchange;
    @Value("${course.publish.routingkey}")
    private String routingkey;

    @Transactional
    public Map<String, Object> previewCourse(Long courseBaseId, Long companyId) {

        if (ObjectUtils.isEmpty(companyId) || ObjectUtils.isEmpty(courseBaseId)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);//请求参数不能为空
        }

        //1.获取coursepub表
        CoursePub coursePub = generateCoursePub(courseBaseId, companyId,false);

        //2.获取dateMap数据
        Map<String, Object> map = generateDateMap(coursePub);

        //3.返回Map
        return map;
    }

    private CoursePub generateCoursePub(Long courseId, Long companyId,Boolean isPublish) {
        CourseBaseDTO courseBaseDTO = courseBaseService.getCourseBaseById(courseId, companyId);
        String auditStatus = courseBaseDTO.getAuditStatus();
        if (isPublish) {
            // 课程发布判断的状态
            if (!(CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus))) {
                ExceptionCast.cast(ContentErrorCode.E_120015);
            }
        }else{
            // 课程预览判断的状态
            if (CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus)||
                    CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus)||
                    CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)
            ) {
                ExceptionCast.cast(ContentErrorCode.E_120015);
            }
        }

        LambdaQueryWrapper<CourseMarket> courseMarketWrapper = new LambdaQueryWrapper<>();
        courseMarketWrapper.eq(CourseMarket::getCourseId, courseId);
        CourseMarket courseMarket = courseMarketService.getOne(courseMarketWrapper);
        if (ObjectUtils.isEmpty(courseMarket)) {
            ExceptionCast.cast(ContentErrorCode.E_120101);//查询的课程营销信息不存在
        }
        String charge = courseMarket.getCharge();
        Float price = courseMarket.getPrice();

        // teachplan --JSON
        //    允许为空,不作判断
        TeachplanDTO teachplanDTO = teachplanService.queryTreeNodesByCourseId(courseId, companyId);

        // courseteacher --JSON
        //    不作判断
        List<CourseTeacherDTO> teacherDTOS = courseTeacherService.queryCourseTeacherList(courseId, companyId);

        // feign接口:
        //    mt st分类名称
        RestResponse<CourseCategoryDTO> mtResponse = systemApiAgent.getCourseCategoryById4s(courseBaseDTO.getMt());
        if (!(mtResponse.isSuccessful())) {
            ExceptionCast.castWithCodeAndDesc(mtResponse.getCode(), mtResponse.getMsg());
        }
        RestResponse<CourseCategoryDTO> stResponse = systemApiAgent.getCourseCategoryById4s(courseBaseDTO.getSt());
        if (!(stResponse.isSuccessful())) {
            ExceptionCast.castWithCodeAndDesc(stResponse.getCode(), stResponse.getMsg());
        }

//2.组装coursepub数据

        CoursePub coursePub = CoursePubConvert.INSTANCE.courseBase2coursePub(courseBaseDTO);
        String marketjson = JSON.toJSONString(courseMarket);
        coursePub.setMarket(marketjson);

        coursePub.setPrice(price);
        coursePub.setCharge(charge);

        String teachersjson = JSON.toJSONString(teacherDTOS);
        coursePub.setTeachers(teachersjson);

        String teachplanjson = JSON.toJSONString(teachplanDTO);
        coursePub.setTeachplan(teachplanjson);


        coursePub.setMtName(mtResponse.getResult().getName());
        coursePub.setStName(stResponse.getResult().getName());
        coursePub.setCourseId(courseId);



//3.修改或保存coursepub

        LambdaQueryWrapper<CoursePub> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CoursePub::getCourseId, courseId);
        CoursePub querypub = this.getOne(queryWrapper);


        Boolean result = false;
        if (ObjectUtils.isEmpty(querypub)) {
            //不存在,保存
            coursePub.setId(null);
            result=this.save(coursePub);

        } else {
            //存在,修改
            coursePub.setId(querypub.getId());
            result = this.updateById(coursePub);
        }

        if (!result) {
            ExceptionCast.cast(ContentErrorCode.E_120205);//课程发布数据保存失败
        }

//4.返回coursepub

        return coursePub;
    }

    //获取dateMap数据
    private Map<String, Object> generateDateMap(CoursePub coursePub) {
        // 1.创建出数据模型
        HashMap<String, Object> dataMap = new HashMap<>();

        //${coursePub.xxxx}
        dataMap.put(CoursePubTemplateKey.COURSEPUB, coursePub);

        //${courseMarket.xxxx}
        String market = coursePub.getMarket();
        CourseMarket courseMarket = JSON.parseObject(market, CourseMarket.class);
        dataMap.put(CoursePubTemplateKey.COURSEMARKET, courseMarket);

        //${courseTeachModeEnums}
        dataMap.put(CoursePubTemplateKey.COURSETEACHMODEENUMS, CourseModeEnum.values());

        //${teachplanNode}
        String teachplan = coursePub.getTeachplan();
        TeachplanDTO teachplanDTO = JsonUtil.jsonToObject(teachplan, TeachplanDTO.class);
        dataMap.put(CoursePubTemplateKey.TEACHPLANNODE,teachplanDTO);

        //${teachers}
        String teachersListJson = coursePub.getTeachers();
        List<CourseTeacherDTO> teacherDTOSJson = JsonUtil.jsonToList(teachersListJson, CourseTeacherDTO.class);
        dataMap.put(CoursePubTemplateKey.COURSETEACHER,teacherDTOSJson);


        return dataMap;
    }


    @Transactional
    public void publish(Long courseBaseId, Long companyId, boolean isResend) {
        //1.判断关键数据
        if (ObjectUtils.isEmpty(courseBaseId) ||
                ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        CoursePubMsg coursePubMsg = null;
        //2.判断是否是从新发送消息，如果是，没有必要创建CoursePub和CoursePubMsg数据了
        if (isResend) {
            // 查询课程发布消息表的数据即可
            LambdaQueryWrapper<CoursePubMsg> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(CoursePubMsg::getCourseId, courseBaseId);
            queryWrapper.eq(CoursePubMsg::getCompanyId, companyId);

            coursePubMsg = coursePubMsgService.getOne(queryWrapper);

            // 如果在定时器重新发送消息时，消息表的数据不存在
            // 记录消息并结束该方法
            if (ObjectUtils.isEmpty(coursePubMsg)) {
                log.error(ContentErrorCode.E_120203.getDesc() + ",courseBaseId 信息：{}", courseBaseId);
                return;
            }
        } else {
            //3.保存数据
            CoursePub coursePub = this.generateCoursePub(courseBaseId, companyId, true);
            coursePubMsg = new CoursePubMsg();
            coursePubMsg.setPubId(coursePub.getId());
            coursePubMsg.setCourseId(coursePub.getCourseId());
            coursePubMsg.setCompanyId(coursePub.getCompanyId());
            coursePubMsg.setPubName(coursePub.getName());
            // 发送消息默认的状态：未发送成功
            coursePubMsg.setPubStatus(CoursePubMsg.UNSENT);
            boolean result = coursePubMsgService.save(coursePubMsg);

            if (!result) {
                ExceptionCast.cast(ContentErrorCode.E_120206);
            }
        }
        //4.发送消息给MQ
        CorrelationData correlationData = new CorrelationData(coursePubMsg.getPubId().toString());

        correlationData.getFuture().addCallback(
                /* mq的交换机接受消息，但不知道是否处理成功 */
                confirm -> {
                    boolean ack = confirm.isAck();
                    if (ack) {
                        // 修改业务数据和消息表的状态
                        execuChangeLocalStatusData(correlationData.getId());
                    } else {
                        // 记录错误消息，并不操作业务数据和消息表
                        log.error(ContentErrorCode.E_120206.getDesc()+",业务数据为CoursePubId：{}",correlationData.getId());
                    }
                },
                /* mq的服务异常，没有接收到消息 */
                throwable -> {
                    log.error(ContentErrorCode.E_120207.getDesc()+",业务数据为CoursePubId：{}  erroMsg: {}",
                            correlationData.getId(),
                            throwable.getMessage());
                }
        );
        String msgJsonString = JsonUtil.objectTojson(coursePubMsg);

        rabbitTemplate.convertAndSend(exchange,routingkey,msgJsonString,correlationData);

    }

    /*
     * 修改本地数据的状态值：
     *       0.判断消息是否已经修改
     *       1.CourseBase
     *           审核状态：课程已发布
     *       2.CoursePubMsg
     *           发送成功的状态：0->1
     * */
    @Transactional
    public  void execuChangeLocalStatusData(String coursePubId) {

        // 0.判断消息是否已经修改
        // 查询coursePubMsg表中的数据并判断其状态
        // CoursePubMsg中的id和CoursePub表的id是唯一、一致
        // select * from course_pub_msg where pubid = ? and pubStatus = ?
        LambdaQueryWrapper<CoursePubMsg> pubMsgQueryWrapper = new LambdaQueryWrapper<>();
        pubMsgQueryWrapper.eq(CoursePubMsg::getPubId, new Long(coursePubId));
        pubMsgQueryWrapper.eq(CoursePubMsg::getPubStatus, CoursePubMsg.UNSENT);

        CoursePubMsg coursePubMsg = coursePubMsgService.getOne(pubMsgQueryWrapper);
        if (ObjectUtils.isEmpty(coursePubMsg)) {
            log.info("修改消息数据已经处理，无需操作，CoursPubId：{}",coursePubId);
            return;
        }



        // 1. CourseBase
        // 审核状态：课程已发布
        Long courseId = coursePubMsg.getCourseId();

        // update course_base set auditStatus = ? where id = ?
        LambdaUpdateWrapper<CourseBase> baseUpdateWrapper = new LambdaUpdateWrapper<>();
        baseUpdateWrapper.set(CourseBase::getAuditStatus, CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode());
        baseUpdateWrapper.eq(CourseBase::getId, courseId);

        boolean baseResult = courseBaseService.update(baseUpdateWrapper);
        if (!baseResult) {
            log.error("修改消课程审核状态失败，CoursPubId：{}",coursePubId);
            return;
        }


        // 2.CoursePubMsg
        // 发送成功的状态：0->1
        // update set course_pub_msg set pub_status = ? where pub_id = ?
        LambdaUpdateWrapper<CoursePubMsg> pubMsgUpdateWrapper = new LambdaUpdateWrapper<>();
        pubMsgUpdateWrapper.set(CoursePubMsg::getPubStatus,CoursePubMsg.SENT);
        pubMsgUpdateWrapper.eq(CoursePubMsg::getPubId, coursePubMsg.getPubId());

        boolean pubResult = coursePubMsgService.update(pubMsgUpdateWrapper);
        if (!pubResult) {
            log.error("修改消息表的状态失败，CoursPubId：{}",coursePubId);

            // 要保证数据的一致性
            ExceptionCast.cast(ContentErrorCode.E_120206);
        }

    }
}
